package com.tcoding.client.extend.render;

import com.tcoding.client.controller.test.model.TestDataVO;
import javafx.beans.property.ListProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import lombok.extern.slf4j.Slf4j;
import org.controlsfx.control.action.ActionUtils;
import org.controlsfx.control.tableview2.FilteredTableColumn;
import org.controlsfx.control.tableview2.FilteredTableView;
import org.controlsfx.control.tableview2.actions.ColumnFixAction;
import org.controlsfx.control.tableview2.actions.RowFixAction;
import org.controlsfx.control.tableview2.filter.filtereditor.SouthFilter;
import org.controlsfx.control.tableview2.filter.popupfilter.PopupFilter;
import org.controlsfx.control.tableview2.filter.popupfilter.PopupStringFilter;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Function;

/**
 * @author 唐全成
 * @Date: 2022/9/21 13:27
 * @description
 **/
@Slf4j
public class FilterTableExtend<T> {


    private ObservableList<TableColumn<T, ?>> columns;

    private LinkedList<TableColumnSouthFilterMap<T>> columnSouthFilterMaps;


    public void register(FilteredTableView<T> filteredTableView, ListProperty<T> tableData , EventHandler<ActionEvent> addHandler ){
        filteredTableView.getStyleClass().addAll( "cf-scroll-bar-style");

        filteredTableView.setTableMenuButtonVisible(true);
        filteredTableView.setColumnFixingEnabled(true);
        filteredTableView.setEditable(true);

        FilteredList<T> filteredData = new FilteredList<>(tableData, p -> true);
        filteredTableView.setItems(filteredData);
        FilteredTableView.configureForFiltering(filteredTableView, tableData);

        //注册首行右键事件
        filteredTableView.setRowHeaderContextMenuFactory((i, data) -> {
            ContextMenu contextMenu = ActionUtils.createContextMenu(Arrays.asList(new RowFixAction(filteredTableView, i), ActionUtils.ACTION_SEPARATOR));
            if (data != null) {
                final MenuItem menuItem = new MenuItem("删除此行" );
                menuItem.setOnAction(e -> {
                    if (i >= 0) {
                        final ObservableList<T> items = filteredTableView.getItems();
                        if (items instanceof SortedList) {
                            int sourceIndex = ((SortedList<TestDataVO>) items).getSourceIndexFor(tableData, i);
                            tableData.remove(sourceIndex);
                        } else {
                            tableData.remove(i.intValue());
                        }
                    }
                });
                contextMenu.getItems().add(menuItem);
            }
            final MenuItem menuItemAdd = new MenuItem("新增一条");
            menuItemAdd.setOnAction(addHandler);
            contextMenu.getItems().add(menuItemAdd);
            return contextMenu;
        });
        columns = filteredTableView.getColumns();
        //注册表格头部右键冻结菜单
        this.initContextMenu(columns);
        //注册表格头部弹出式过滤
        this.filterAction(columns);
        //注册表格下拉过滤
        this.initColumnSouthFilterMap(columns);
    }

    /**
     * 切换过滤方式
     * @param n
     */
    public void setupFilter(Boolean n){
        if (n) {
            southNodeFilterAction();
                for (TableColumnSouthFilterMap<T> columnSouthFilterMap : columnSouthFilterMaps) {
                    columnSouthFilterMap.getFilteredTableColumn().setSouthNode(columnSouthFilterMap.getSouthFilter());
                }
            } else {
            filterAction(columns);
            for (TableColumnSouthFilterMap<T> columnSouthFilterMap : columnSouthFilterMaps) {
                columnSouthFilterMap.getFilteredTableColumn().setSouthNode(null);
            }
        }
    }

    public void registerCustomerSouthFilter(FilteredTableColumn<T, ?> column,SouthFilter<T, String> southFilter){

        for (TableColumnSouthFilterMap<T> columnSouthFilterMap : columnSouthFilterMaps) {
            if(column.equals(columnSouthFilterMap.getFilteredTableColumn())){
                columnSouthFilterMap.setSouthFilter(southFilter);
            }
        }
    }


    private void initContextMenu( ObservableList<TableColumn<T,?>> columns){
        for (TableColumn<T,?> column : columns) {
            ContextMenu cm = ActionUtils.createContextMenu(Collections.singletonList(new ColumnFixAction(column)));
            column.setContextMenu(cm);
        }
    }

    private void filterAction(ObservableList<TableColumn<T,?>> columns) {
        for (TableColumn<T,?> column : columns) {
            FilteredTableColumn<T,?> filteredTableColumn = ( FilteredTableColumn<T,?>)column;
            PopupFilter<T, ?> popupCol1Filter = new PopupStringFilter<>(filteredTableColumn);
            filteredTableColumn.setOnFilterAction(e -> popupCol1Filter.showPopup());
        }
    }

    private void initColumnSouthFilterMap(ObservableList<TableColumn<T,?>> columns){
        columnSouthFilterMaps = new LinkedList<>();
        for (TableColumn<T, ?> column : columns) {
            try {
                FilteredTableColumn<T,String> filteredTableColumn = ( FilteredTableColumn<T,String>)column;
                SouthFilter<T, String> southFilter = new SouthFilter<>(filteredTableColumn, String.class);
                TableColumnSouthFilterMap<T> tTableColumnSouthFilterMap = new TableColumnSouthFilterMap<>(filteredTableColumn, southFilter);
                columnSouthFilterMaps.add(tTableColumnSouthFilterMap);

            }catch (Exception e){
                log.error("列类型强制转换失败：{}",e.getMessage());
            }

        }

    }

    private void southNodeFilterAction() {
        for (TableColumnSouthFilterMap<T> columnSouthFilterMap : columnSouthFilterMaps) {
            FilteredTableColumn<T, ?> filteredTableColumn = columnSouthFilterMap.getFilteredTableColumn();
            filteredTableColumn.setOnFilterAction(e->{
                if (filteredTableColumn.getPredicate() != null) {
                    columnSouthFilterMap.getSouthFilter().getFilterEditor().cancelFilter();
                }
            });
        }
    }

    static class TableColumnSouthFilterMap<T>{
        FilteredTableColumn<T,?> filteredTableColumn;
        SouthFilter<T, String> southFilter;

        public TableColumnSouthFilterMap(FilteredTableColumn<T, ?> filteredTableColumn, SouthFilter<T, String> southFilter) {
            this.filteredTableColumn = filteredTableColumn;
            this.southFilter = southFilter;
        }

        public TableColumnSouthFilterMap() {
        }

        public FilteredTableColumn<T, ?> getFilteredTableColumn() {
            return filteredTableColumn;
        }

        public void setFilteredTableColumn(FilteredTableColumn<T, ?> filteredTableColumn) {
            this.filteredTableColumn = filteredTableColumn;
        }

        public SouthFilter<T, ?> getSouthFilter() {
            return southFilter;
        }

        public void setSouthFilter(SouthFilter<T, String> southFilter) {
            this.southFilter = southFilter;
        }
    }
}
